RestTemplate 操作详细笔记

作者: 李多多 日期: 2020-06-27
Spring Cloud
RestTemplate 操作详细笔记

RestTemplate 介绍

  • spring3.0 开始支持
  • Http 请求工具
  • 该工具与 springboot 或 springcloud 无关
  • 提供常见的 REST 请求模版
  • 例如支持 GET、PUT、POST、DELETE
  • 通用请求方法 –> exchange 和 execute
  • 实现 RestOperations 接口
  • 该接口定义了常见的 RESTful 操作

    1.GET 操作

    首先在 provider 中定义一个 hello2 接口:
@GetMapping("/hello2")
public String hello2(String name){
return "hello "+name;
}

接下来,我们在 consumer 去访问这个接囗,调用 RestTemplate 中 的 GET 请求。 可以看到,在 RestTemplate 中,关于 GET 请求,一共有两大类方法:

这两大类方法实际上是重载的,唯一不同的,就是返回值类型。 getForObject 返回的是一个对象,这个对象就是服务端返回的具体值。getForEntiey 返回的是一个 ResponseEntity,这个 ResponseEntity 中除了服务端返回的具体数据外,还保留了 Http 应头的数据。

@GetMapping("/hello4")
public void hello4(){
String s1 = restTemplate.getForObject("http://provider/hello2?name={1}",String.class,"javaone");
System.out.println(s1);
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://provider/hello2", String.class, "javaone");
String body = responseEntity.getBody();
System.out.println("body:"+body);
HttpStatus statusCode = responseEntity.getStatusCode();
System.out.println("HttpStatus:"+statusCode);
int statusCodeValue = responseEntity.getStatusCodeValue();
System.out.println("statusCodeValue:"+statusCodeValue);
HttpHeaders headers = responseEntity.getHeaders();
Set<String> keySet = headers.keySet();
System.out.println("---------headers--------");
for (String s : keySet) {
System.out.println(s+":"+headers.get(s)+"///");
}
}

这里大家可以看到,getForObject 直接拿到了服务的返回值,getForEntity 不仅仅拿到服务的返回值, 还拿到 http 应的状态码。然后,后动 Eureka Server、provider 以及 consumer,访问 consumer 中的 hello4 接囗,既可以看到请求结果。

看清楚两者的区别之舌,接下来看下两个各自的重载方法,getForObject 和 getForEntity 分别有三个重载方法,两者的三个重载方法基本都是一致的。所以,这里,我们主要看其中一种。三个重载方法, 其实代表了三种不同的传参方式。

@GetMapping("/hello5")
public void hello5(){
String s1 = restTemplate.getForObject("http://provider/hello2?name={1}",String.class,"javatwo");
System.out.println("1:"+s1);
HashMap<String, Object> map = new HashMap<>();
map.put("name","zhangsan");
s1 = restTemplate.getForObject("http://provider/hello2?name={name}", String.class,map);
System.out.println("2:"+s1);
try {
String url = "http://provider/hello2?name="+ URLEncoder.encode("李四","UTF-8");
URI uri = URI.create(url);
s1 = restTemplate.getForObject(uri, String.class);
System.out.println("3:"+s1);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}

小结:

  1. getForObject 和 getForEntity 返回值区别:
  • getForObject 返回一个对象 (服务返回的具体值)
  • getForEntity 不仅返回具体数据 还可以返回状态码 头信息…
  1. getForObject 和 getForEntity 三种重载方式的类似
  • Object… –> 占位符 (?xxx={1}, xx.class, “xxxxx”)
  • Map<String, ?> –> 占位符为自定义 key (name) 需要提前声明 map (?xxx={key}, xx.class, 返回的 map)
  • URI –> 字符串中包含中文的需要转码才能创建为 URI 在被调用

2.POST 操作

2.1 准备工作

因为 post 请求可能是 k/v 或是 json 形式,需要提供 2 种接口,传参对象需要创建一个 model, 为了以后方便使用直接新建一个普通的 maven 项目作为 commons 模块管理。

创建一个 User 类。

@Data
@ToString
public class User {
private Integer id;
private String name;
private String nickName;
}

然后 provider 和 consumer 分别引用 commons 模块依赖

<dependency>
<groupId>com.example</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

2.2 provider 提供 2 个接口

// key/value形式传递
@PostMapping("/user1")
public User addUser1(User user){
return user;
}

//json传递
@PostMapping("/user2")
public User addUser2(@RequestBody User user){
return user;
}

接下来,我们在 consumer 中调这两个 POST 接囗。

这里的 post 和前面的 get 很像,只是多出来了三个方法,就是 postForLocation,另外,两个 postForObject 和 postForEntiy 和前面 get 基不一致,所以这里我们主要来看 postForObject, 看完之后,我们再来看这个额外的 postForLocation。

@GetMapping("/hello6")
public void hello6(){
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username","javajava");
map.add("password","123456");
map.add("id",666);
User user = restTemplate.postForObject("http://provider/user1", map, User.class);
System.out.println("1:"+user);
user.setId(888);
user = restTemplate.postForObject("http://provider/user2", user, User.class);
System.out.println("2:"+user);
}

post 参数到底是 k/v 形式还是 json 形式,主要看第二个参数,如果第二个参数是 MultiValueMap,则参数是以 k/v 形来传递的。 如果是一个普通对象,则参数是以的 son 形式 传递。

最后再看看一下 postForLocation。有的时候,当执行完一个 post 请求之后,立马要进行重定向, 一个非常常见的场景就是注册,注册是一个 post 请求,注册完成之后,立马重定向到登录页面去登录。对于这种场景,我们就可以便用 postForLocation。

首先我们在 provider 上提供一个用户注册接囗:

@Controller
public class RegisterController {

@PostMapping("/register")
public String register(User user){
return "redirect:http://provider/loginPage?username="+user.getUsername();
}

@GetMapping("/loginPage")
@ResponseBody
public String loginPage(String username){
return "loginPage:"+username;
}
}

注意:

这里的 post 接口,响应一定是 302,否则 postForLocaton 无效。
重定向的地址,一定要写成绝对路径,不要写成相对路径,否则在 consumer 中调用时会出问题

@GetMapping("/hello7")
public void hello7() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javajava");
map.add("password", "123456");
map.add("id", 666);
//这就是postForLocation,调用该方法返回的是一个Uri,Uri就是重定向的地址(里面包含重定向的参数),拿到Uri之后,就可以直接发送新的请求了
URI uri = restTemplate.postForLocation("http://provider/register", map);
String s = restTemplate.getForObject(uri, String.class);
System.out.println(s);

}

3.PUT

首先在 provider 提供一个 put 接口:

@PutMapping("/user11")
public void updateUser1(User user1){ //k/v形式
System.out.println(user1);
}

@PutMapping("/user12")
public void updateUser2(@RequestBody User user2){ //json形式
System.out.println(user2);
}

在 consumer 中调用该接口,和上面 post 类似:

@GetMapping("/hello8")
public void hello8() {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("username", "javajava");
map.add("password", "123456");
map.add("id", 666);
restTemplate.put("http://provider/user11",map);
User user = new User();
user.setId(98);
user.setUsername("zhangsan");
user.setPassword("123456");
restTemplate.put("http://provider/user12",user);
}

4.DELETE

首先在 provider 提供一个 delete 接口:

@DeleteMapping("/user13")
public void deleteUser1(Integer id){
System.out.println(id);
}

@DeleteMapping("/user14/{id}")
public void deleteUser2(@PathVariable Integer id){
System.out.println(id);
}

在 consumer 中调用这两个删除接口 (delete 中参数的传递,也支持 map,这块实际上和 get 是一样的):

@GetMapping("/hello9")
public void hello9() {
restTemplate.delete("http://provider/user13?id={1}",99);
restTemplate.delete("http://provider/user14/{1}",99);
}

示例代码地址:https://github.com/astronger/springcloud-simple-samples